package com.project.quiktask.controller;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.ParseException;
import java.util.Collections;
import java.util.Vector;

import com.project.quiktask.Task;
import com.project.quiktask.datastore.FileLoader;
import com.project.quiktask.util.Result;
import com.project.quiktask.util.Variable;

public class ViewHandler implements CommandHandler {

	private static final String FEEDBACK_VIEW_BY_TIME = "Viewing all tasks, sorted by time.";
	private static final String FEEDBACK_VIEW_BY_IMPORTANCE = "Viewing all tasks, sorted by importance.";
	private static final String FEEDBACK_VIEW_ALL = "Viewing all tasks.";

	Task newTask = new Task();
	Vector<Task> allTasks = new Vector<Task>();
	
	public ViewHandler() {
	}
	
	public Result execute(String commandContent) {
		
		Result loadFileResult = loadStorageFile();
		
		if (isFileLoadedSuccessfully(loadFileResult)) {
			Result feedbackResult = executeViewCommand(commandContent);
			return feedbackResult;
		}
		else
			return loadFileResult;
	}
	
	// TODO better handling of finally and catch
	@SuppressWarnings("finally")
	public Result loadStorageFile() {
		try {
			FileLoader loader = new FileLoader(Variable.STORAGE_FILE_NAME);
			allTasks = loader.load();
		} catch (FileNotFoundException e) {
			return new Result(Variable.FEEDBACK_ERROR_FILE_NOT_FOUND);
		} catch (IOException e) {
			e.printStackTrace();
			return new Result(Variable.FEEDBACK_ERROR_GENERAL);
		} catch (ParseException e) {
			e.printStackTrace();
			return new Result(Variable.FEEDBACK_ERROR_GENERAL);
		} finally {
			return new Result(Variable.FEEDBACK_SUCCESS_FILE_LOADED);
		}
	}
	
	// TODO view all
	public Result executeViewCommand(String commandContent) {
		if (isViewByTime(commandContent)) {
			Result result = handleViewTimeCommand();
			return result;
		} else if (isViewByImportance(commandContent)) {
			Result result = handleViewImportanceCommand();
			return result;
		} /*else if (isViewAllTasks(commandContent)) {
			Result result = handleViewAllCommand();
			return result;
		}*/
		else
			return new Result(Variable.FEEDBACK_COMMAND_INVALID);
	}
	
	public Result handleViewTimeCommand() {
		Vector<Task> sortedTasks = sortByTime(allTasks);
		Result result = new Result(FEEDBACK_VIEW_BY_TIME, sortedTasks);
		return result;
	}
	
	public Result handleViewImportanceCommand() {
		Vector<Task> sortedTasks = sortByImportance();
		Result result = new Result(FEEDBACK_VIEW_BY_IMPORTANCE, sortedTasks);
		return result;
	}
	
	
	// TODO sorted order if view all
	/*public Result handleViewAllCommand() {
		Result result = new Result(FEEDBACK_VIEW_ALL, allTasks);
		return result;\
	}*/
	
	public Vector<Task> sortByTime(Vector<Task> unsortedTasks) {
		Vector<Task> floatingTasks = new Vector<Task>();
		Vector<Task> nonFloatingTasks = new Vector<Task>();
		
		for (int i=0; i < unsortedTasks.size(); i++) {
			Task currentTask = unsortedTasks.get(i);
			if (isFloatingTask(currentTask))
				floatingTasks.add(currentTask);
			else
				nonFloatingTasks.add(currentTask);
		}
	
		// TODO settle sorting tasks of same tier
		Vector<Task> sortedTasks = populateSortedTasksVector(nonFloatingTasks, floatingTasks);
		
		return sortedTasks;
	}
		
	public Vector<Task> populateSortedTasksVector(Vector<Task> nonFloatingTasks, 
			Vector<Task> floatingTasks) {
		
		Vector<Task> sortedTasks = new Vector<Task>();

		TimeComparator timeComparator = new TimeComparator();
		Collections.sort(nonFloatingTasks, timeComparator);
		sortedTasks = appendToExistingVector(sortedTasks, nonFloatingTasks);
		sortedTasks = appendToExistingVector(sortedTasks, floatingTasks);

		return sortedTasks;
	}
	
    public Vector<Task> appendToExistingVector(Vector<Task> sortedTasks, Vector<Task> vector) {
    	for (int i=0; i<vector.size(); i++) {
    		Task currentTask = vector.get(i);
    		sortedTasks.add(currentTask);
    	}
    	return sortedTasks;		
    }
    
	public Vector<Task> sortByImportance() {
	
		ImportanceComparator importanceComparator = new ImportanceComparator();
		Collections.sort(allTasks, importanceComparator);

		Vector<Task> importantTasks = new Vector<Task>();
		Vector<Task> notImportantTasks = new Vector<Task>();
		Vector<Task> sortedTasks = new Vector<Task>();
	
		// sort non-important tasks by time
		for (int i=0; i < allTasks.size(); i++) {
			Task currentTask = allTasks.get(i);
			if (currentTask.getImportance())
				importantTasks.add(currentTask);
			else
				notImportantTasks.add(currentTask);
		}
				
		importantTasks = sortByTime(importantTasks);
		notImportantTasks = sortByTime(notImportantTasks);

		sortedTasks = appendToExistingVector(sortedTasks, importantTasks);
		sortedTasks = appendToExistingVector(sortedTasks, notImportantTasks);
		
		return sortedTasks;
	}
	
	public boolean isFileLoadedSuccessfully(Result result) {
		if (result.getFeedback() == Variable.FEEDBACK_SUCCESS_FILE_LOADED)
			return true;
		else
			return false;
	}
	
	public boolean isViewByTime(String command) {
		if (command.equalsIgnoreCase("time") || 
				command.equalsIgnoreCase("t"))
			return true;
		else
			return false;
	}
	
	public boolean isViewByImportance(String command) {
		if (command.equalsIgnoreCase("importance") ||
				command.equalsIgnoreCase("i"))
			return true;
		else
			return false;
	}
	
	public boolean isViewAllTasks(String command) {
		if (command.equalsIgnoreCase("all") ||
				command.equalsIgnoreCase("a") ||
				command.equalsIgnoreCase(""))
			return true;
		else
			return false;
	}
	
    public boolean isFloatingTask(Task task) {
    	if (task.getStartDate() == null && 
    			task.getDeadlineDate() == null && 
    			task.getEndDate() == null) 
    		return true;
    	else 
    		return false;
    }
    
    public boolean isDeadlineTask(Task task) {
    	if (task.getDeadlineDate() != null || 
    			task.getDeadlineTime() != null)
    		return true;
    	else
    		return false;
    }

	@Override
	public Result undo() {
		return new Result(Variable.CANNOT_UNDO_VIEW_COMMAND);
	}
}
